package chat7me_1223.server;

import chat7me_1223.server.dao.UserDao;
import chat7me_1223.server.utils.IOUtil;
import chat7me_1223.server.vo.UserData;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLException;
import java.util.HashMap;

public class Server {
    public static void main(String[] args) {
        Server server=new Server();
        server.start();
    }

    //存储所有的在线用户对象和此对象的用户名
    HashMap<String, UserData>  users_onLine=new HashMap<>();
    //1.构造方法
    ServerSocket  server_socket=null;
    Server(){
        try {
            System.out.println("启动服务器中....");
            server_socket=new ServerSocket(8088);
            System.out.println("服务器启动成功");
        } catch (IOException e) {
            System.out.println("服务器启动异常"+e.getMessage());
        }
    }

    //2.start方法启动服务端
    private void start() {
        try {
            while(true){
                System.out.println("服务器等待客户端连接..wait..wait..");
                Socket s=server_socket.accept();
                System.out.println(s.getInetAddress()+"客户端连接成功..connected");
                ClientService  cService=new ClientService(s);
                cService.start();
            }
        }catch (IOException e){
            System.out.println("服务器异常"+e.getMessage());
        }
    }



    //一定要注意： 服务端和客户端使用的这些常量值一定要一样(eg: LOGIN_REQUEST的值在服务端和客户端都要是1)
    //可以将这些变量放入到一个单独的java类中，这样服务端和客户端就可以复用这些常量值
    public static final  short  LOGIN_REQUEST=1;
    public static final  short  REGISTER_REQUEST=2;
    public static final  short  SEND_TEXT_REQUEST=3;

    public static final  short  LOGIN_RESPONSE=1;
    public static final  short  REGISTER_RESPONSE=2;
    public static final  short  SEND_TEXT_TO_ALL_RESPONSE=3;
    public static final  short  USER_LIST_RESPONSE=4;
    class ClientService extends  Thread{
        Socket socket;
        InputStream in;
        OutputStream out;
        UserData userClient;//本线程服务的客户端登录的用户
        ClientService(Socket thread_socket){
            socket=thread_socket;
        }
        public void run() {
            try {
                in=socket.getInputStream();
                out=socket.getOutputStream();
                int cmd=-1;
                while( (cmd=in.read())!=-1 ){
                    switch (cmd){
                        case LOGIN_REQUEST:
                            doLogin();
                            reShowFriendsList();
                            break;
                        case REGISTER_REQUEST:
                            doRegister();
                            break;
                        case SEND_TEXT_REQUEST:
                            sendTextToAll();
                            break;
                    }
                }
            } catch (Exception e) {
                System.out.println(socket.getInetAddress()+"客户端下线了(无法读取此客户端数据)");
            }finally {
                if(users_onLine!=null && users_onLine.size()!=0 && userClient!=null && userClient.getUsername()!=null){
                    users_onLine.remove(userClient.getUsername());//将下线用户从HashMap  users中删除
                    System.out.println(socket.getInetAddress()+"客户端下线了");
                }
                try{
                    reShowFriendsList();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }


        public void doLogin()throws  Exception{
            try {
                String username = IOUtil.readString(in);//读取两次客户端发送的数据(账号和密码)
                String password = IOUtil.readString(in);//因为客户端发送了两次数据(第一次发送账号第二次发送密码)
                if (!checkUserHasLoginByName(username)) {
                    UserData userData = new UserData(username, password);
                    if (UserDao.login(userData)) {
                        this.userClient = userData;
                        userClient.setSocket(socket);
                        users_onLine.put(username,userClient);
                        System.out.println("服务端提示信息: 一个用户登录成功,ip"+socket.getInetAddress()+"，在线人数："+users_onLine.size());
                        reShowFriendsList();
                        IOUtil.writeShort(LOGIN_RESPONSE,out);
                        IOUtil.writeString("loginSuccess",out);
                    }else{
                        IOUtil.writeShort(LOGIN_RESPONSE,out);
                        IOUtil.writeString("用户名或密码错误",out);
                    }
                }else{
                    IOUtil.writeShort(LOGIN_RESPONSE,out);
                    IOUtil.writeString("账号"+username+"处于登录状态",out);
                }
            }catch (SQLException e){
                System.out.println("服务端提示信息: 登录异常，原因："+e.getMessage());
            }
        }

        private boolean checkUserHasLoginByName(String username) {
            return  users_onLine.containsKey(username);
        }


        //给客户端返回在线好友列表
        public void reShowFriendsList() throws  IOException{
            try {
                StringBuffer onLineUsers_StringBuffer = new StringBuffer();
                for (String username_key : users_onLine.keySet()) {
                    onLineUsers_StringBuffer.append(username_key);
                }
                for (UserData userData : users_onLine.values()) {
                    OutputStream out = userData.getSocket().getOutputStream();
                    IOUtil.writeShort(USER_LIST_RESPONSE, out);
                    IOUtil.writeString(onLineUsers_StringBuffer.toString(), out);
                }
            }catch (IOException e){
                System.out.println("服务端提示信息: 刷新在线好友列表异常，原因："+e.getMessage());
                throw e;
            }
        }



        private void doRegister()throws  Exception {
            boolean reg_success=false;
            try{
                String username = IOUtil.readString(in);//读取两次客户端发送的数据(账号和密码)
                String password = IOUtil.readString(in);//因为客户端发送了两次数据(第一次发送账号第二次发送密码)
                UserData userObject_register=new UserData(username,password);
                UserDao.addUser(userObject_register);
                reg_success=true;
                userClient=userObject_register;
                userClient.setSocket(socket);
                users_onLine.put(username,userClient);
            }catch (Exception e){
                IOUtil.writeShort(REGISTER_RESPONSE,out);
                IOUtil.writeString("注册异常，原因："+e.getMessage(),out);
                System.out.println("服务端提示信息: 注册异常，原因："+e.getMessage());
                reg_success=false;
            }
            if(reg_success){
                IOUtil.writeShort(REGISTER_RESPONSE,out);
                IOUtil.writeString("registerSuccess",out);
                reShowFriendsList();
            }

        }


        private void sendTextToAll() throws  Exception{
            try {
                String msg = IOUtil.readString(in);
                for (UserData user_onLine : users_onLine.values()) {
                    if (userClient.getUsername().equals(user_onLine.getUsername())) {
                        continue;
                    }
                    OutputStream out = user_onLine.getSocket().getOutputStream();
                    IOUtil.writeShort(SEND_TEXT_TO_ALL_RESPONSE, out);
                    IOUtil.writeString(userClient.getUsername(), out);
                    IOUtil.writeString(msg, out);
                }
            }catch (Exception e){
                System.out.println("服务端提示信息: 注册异常，原因："+e.getMessage());
                throw  e;
            }

        }





    }


}
